﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Noris.Tools.TraceVisualiser.Interface;
using Noris.Tools.TraceVisualiser.Support;
using Noris.Tools.TraceVisualiser.TraceData;
using Noris.Tools.TraceVisualiser.SqlParser;
using Noris.Tools.TraceVisualiser.Forms;

namespace Noris.Tools.TraceVisualiser.Green.AplServer
{
    public class Func_ShowDeadlock : Func_Base, IFunctionGlobalProvider
    {
		#region IPlugin Members
		/// <summary>
		/// Příznak, že Plugin je aktivní ve standardním běhu (tj. při běžném užiavtelském spuštění).
		/// Plně funkční pluginy tedy vrací true.
		/// Pluginy, které jsou ve vývoji, vrací false, takové jsou zobrazeny / spouštěny pouze v aplikaci, která běží v režimu Debug.
		/// </summary>
		bool IPlugin.Active { get { return true; } }
		#endregion
		#region IFunctionGlobalMenuItem Members
        void IFunctionGlobalProvider.CreateMenuItems(FunctionGlobalDeclareArgs args)
        {
			FunctionMenuItem ddlButton = new FunctionMenuItem(200, "Deadlocky", "Najde všechny deadlocky v trace souborech, které už jsou načteny do paměti." + Environment.NewLine + "Zobrazí jejich detaily.", ToolItemProperties.EnabledDependOnTrace,
				TraceVisualiser.Pics.PicLibrary16.LockRed3_FromFile,
				TraceVisualiser.Pics.PicLibrary22.LockRed3_FromFile) { ToolbarType = ToolItemType.ToolStripDropDownButton };
			ddlButton.SubItems = new List<FunctionMenuItem>();
			ddlButton.SubItems.Add(new FunctionMenuItem(210, "Načtené v paměti"));
			ddlButton.SubItems.Add(new FunctionMenuItem(220, "Všechny = vyhledat i v nenačtených souborech"));
			args.MenuItems.Add(ddlButton);
        }
        /// <summary>
        /// Spuštění funkce
        /// </summary>
        /// <param name="args"></param>
        void IFunctionGlobalProvider.Run(FunctionGlobalRunArgs args)
        {
			switch (args.MenuItem.MenuOrder)
			{
				case 210:
					this._RunInMemory(args);
					break;
				case 220:
					this._RunAllTraces(args);
					break;
			}
        }
		/// <summary>
		/// Hledá deadlocky načtené v paměti
		/// </summary>
		/// <param name="args"></param>
		private void _RunInMemory(FunctionGlobalRunArgs args)
		{
			List<IMasterDetails> nrsItems = this.GetLoadedDetails(args, this._FilterEventDeadlock);
            this._RunShowResults(nrsItems);
		}
		/// <summary>
		/// Hledá deadlocky scanováním dosud nenačtených trace souborů, k nimž přidává deadlocky z paměti = najde vždy všechny deadlocky.
		/// </summary>
		/// <param name="args"></param>
		private void _RunAllTraces(FunctionGlobalRunArgs args)
		{
            this._DataSource = this.GetDataSource(args);
            this._LoadedDetails = this.GetLoadedDetails(args, this._FilterEventDeadlock);
			this._DeadlockList = new List<IMasterDetails>();

            WorkingThread.AddItem(this._RunAllTracesBgr, ProgressFormMode.ShowWithCancel, this._RunAllTracesError, null);
        }
        private void _RunAllTracesBgr()
        {
            TraceDataSource dataSource = this._DataSource;
			
            dataSource.Main.ScanContentOfTrace(false, this._ScanOneEdge, null, this._RunAllTracesProgress);

            foreach (IMasterDetails nrsItem in this._LoadedDetails)
				this._DeadlockList.Add(nrsItem);    // new MasterDetailDeadlock(nrsItem));

            this._RunShowResults(this._DeadlockList);
		}
        private void _RunAllTracesProgress(ProgressData progress)
        {
            WorkingThread.DoProgress(progress);
        }
        private void _RunAllTracesError(Exception exc)
        {
            throw exc;
        }
        /// <summary>
        /// Akce s jedním každým objektem načteným ze vstupních trace souborů.
        /// Filtruje objekty typu Noris.Tools.TraceVisualiser.Green.AplServer.TraceItem, z nich potom pouze ty které jsou IsDeadlock,
        /// a ty pak střádá do this._DeadlockList.
        /// </summary>
        /// <param name="eventEdge"></param>
		private void _ScanOneEdge(IEventEdge eventEdge, TraceData.TraceInfo trace)
		{
			TraceItem item = eventEdge as TraceItem;
            
			if (item == null) return;

			// Jde o deadlock?
			if (item.IsDeadlock)
                this._DeadlockList.Add(new MasterDetailDeadlock(item, trace));
		}
        private TraceDataSource _DataSource;
        private List<IMasterDetails> _LoadedDetails;
		private List<IMasterDetails> _DeadlockList;
        /// <summary>
        /// Zobrazí výsledky
        /// </summary>
        /// <param name="nrsItems"></param>
        private void _RunShowResults(List<IMasterDetails> nrsItems)
        {
            if (nrsItems.Count > 0)
                this.RunShowDetail(nrsItems);
            else
                Dialog.ShowInfo("V paměti dosud není načten žádný trace soubor,\r který by obsahoval informace o deadlocku.");
        }
        #endregion
        #region Práce s eventy - filtrace
        /// <summary>
        /// Filtr: vrátí true, pokud daný EventItem je Deadlock
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private bool _FilterEventDeadlock(IEventItem item)
        {
			// Deadlock je systémový event, který má nastavený StatusInfo = StatusInfoType.Deadlock
            EventSystemItem sysItem = item as EventSystemItem;
            if (sysItem == null) return false;

            return (sysItem.StatusInfo == StatusInfoType.Deadlock && sysItem.Keyword == "ERROR");
        }
        #endregion
		#region Třída pro zachycení dat o deadlocku včetně pokusu o vyhledání důvodu, použitelná pro okno detailů (IMasterDetails)
		protected class MasterDetailDeadlock : IMasterDetails
		{
			internal MasterDetailDeadlock(IMasterDetails detail)
			{
                this._MasterName = detail.MasterName;
                this._DetailBackColor = detail.DetailBackColor;
                this._Details = new List<MasterDetailItem>(detail.Details);
            }
			internal MasterDetailDeadlock(TraceItem item, TraceData.TraceInfo trace)
			{
                this._MasterName = item.LineNumber.ToString() + ": " + item.Time.ToString("HH:mm:ss.fff");
                this._DetailBackColor = Color.Empty;
                this._Details = new List<MasterDetailItem>();

                this._Details.Add(new MasterDetailItem("Trace", trace.FullFileName));
                this._Details.Add(new MasterDetailItem("Trace.Line", item.LineNumber.ToString()));

                this._Details.Add(new MasterDetailItem("BEDepth", item.BEDepth));
                this._Details.Add(new MasterDetailItem("Login", item.Login));
                this._Details.Add(new MasterDetailItem("Stack", Green.AplServer.TraceReader.FormatStackInfo(item.Stack)));
                this._Details.Add(new MasterDetailItem("ThreadId", item.ThreadId));
                this._Details.Add(new MasterDetailItem("RoundtripId", item.RoundtripId));
                this._Details.Add(new MasterDetailItem("PageId", item.PageId));
                this._Details.Add(new MasterDetailItem("Keyword", item.Keyword));
                this._Details.Add(new MasterDetailItem("Method", item.Method));
                this._Details.Add(new MasterDetailItem("Type", item.Type));
                this._Details.Add(new MasterDetailItem("SecureId", item.SecureId));
                this._Details.Add(new MasterDetailItem("StatusInfo", item.StatusInfo.ToString()));

                for (int u = 0; u < item.UserLength; u++)
                    this._Details.Add(new MasterDetailItem("User" + u.ToString(), item.User(u)));
            }
            private string _MasterName;
            private Color _DetailBackColor;
            private List<MasterDetailItem> _Details;
            #region IMasterDetails Members
            string IMasterDetails.MasterName { get { return this._MasterName; } }
            Color IMasterDetails.DetailBackColor { get { return this._DetailBackColor; } }
			IEnumerable<MasterDetailItem> IMasterDetails.Details { get { return this._Details; } }
			#endregion
		}
		#endregion
    }
}
